// console.log(window) //node.js中没有window对象
//  console.log(global) //node.js中有全局global对象

const fs = require('fs');

//读取文件  【异步】
// fs.readFile( './img/spirit.png' , 'utf8', (err, data)=>{
//     //如果出错  则抛出错误
//     if(err)  throw err
//     // 如果写了英文，会出现乱码,需要加一个toString();
//     console.log(data.toString());
// })

//读取文件返回  【同步】
// var data = fs.readFileSync('./img/spirit.png');
// let mimeobj=data.toString();
// console.log(mimeobj);

// 转为base64
// let data = fs.readFileSync('./img/spirit.png','base64');
// console.log(data);


// 写入文件---直接替换整个文件的内容   异步
// fs.writeFile("./img/文本.txt","测试一下真的写入成功了吗？？？",(err)=>{
//     // 如果写入成功 err 会打印 null，
//     // 如果失败打印错误对象
//      console.log(err);
//  })

// 写入文件---方法1追加内容  异步
// const contentToAppend = '\n这是要追加的内容';
// // 文件路径
// const filePath = './img/文本.txt';

// // 使用 appendFile 方法追加内容
// fs.appendFile(filePath, contentToAppend, (err) => {
//   if (err) {
//     console.error('追加内容时出错:', err);
//   } else {
//     console.log('内容已成功追加到文件中');
//   }
// });

// 注意：若文件存在，追加内容，不存在则创建
// 同步
// fs.appendFileSync('./img/index.css','h2{color:green}\n');

// 写入文件---替换内容  异步
// const contentToAppend = '222';

// // 文件路径
// const filePath = './img/文本.txt';

// // 使用 writeFile 方法并设置 flags 为 'a' 以追加内容
// fs.writeFile(filePath, contentToAppend, { flags: 'a' }, (err) => {
//   if (err) {
//     console.error('写入（追加）内容时出错:', err);
//   } else {
//     console.log('内容已成功追加到文件中');
//   }
// });


// 同步，有返回值
// const res = fs.writeFileSync("./img/测试.doc", '这是要写入的内容');
// console.log(res); 返回值是undefined
// 语法：fs.writeFileSync(path,data[, options])
// 特点：writeFile方法是覆盖式写入，后面的内容会将前面的内容覆盖
 
// 参数：path，被写入文件的路径（相对路径或绝对路径）
//       data，要写入的内容，字符串格式
//       options：写入文件的参数配置，默认是utf8编码


// fs.stat():  检测是文件还是目录
// fs.stat('./img',(err, data)=>{
//     if (err) {
//         console.log(err);
//         return;
//     }
//     console.log(`是文件：${data.isFile()}`);  //布尔值
//     console.log(`是目录：${data.isDirectory()}`); //布尔值
// })


// 参数：创建目录的路径      目录读取权限,默认777(可省略)     回调(可省略)
// fs.mkdir('./img/test',(err)=>{ //如果已经存在，会报错
//     if(err) throw err;
//     console.log("创建目录成功");
// })
// fs.mkdirSync('./img/test') //同步创建目录
 

// fs.readdir() 和 fs.readdirSync()读取目录中的所有文件，
// 读取目录中的所有文件，包括目录，返回一个数组
// 同步
// fs.readdir('./',(err,data)=>{  
//     if(err) throw err;
//     console.log("读取目录成功",data);
// })
 
// 异步
// console.log(fs.readdirSync('./'));


// fs.rename() :    重命名      移动文件
// 第一个参数是要重命名的文件路径，第二个参数是新的文件路径包括文件名---如果同文件夹下，就是重命名
// fs.rename('./img/index.html','./img/test/index.css',(err)=>{
//     if(err) throw err;
//     console.log("重命名成功");
// })


// fs.rmdir():  删除目录
// 注意：要确保目录里面没有文件才能成功
// 如果没有该文件夹，会报错
// fs.rmdir('./img/test',err=>{
//     if(err) throw err;
//     console.log("删除目录成功");
// })


// fs.unlink()：  删除文件
// 如果没有该文件，会报错
// fs.unlink('./img/测试.doc',err=>{
//     if(err) throw err;
//     console.log("删除文件成功");
//  })


// fs.createReadStream() 从文件流中读取数据
// 从文件流中读取数据
// var readStream = fs.createReadStream('./img/文本.txt');
// var count = 0;
// var str = '';
// // 监听读取的状态
// readStream.on('data',data=>{
//     str+=data;
//     count++;
// })
// // 监听什么时候读取完
// readStream.on('end',()=>{
//     console.log(str);
//     console.log(count);
// })
// // 打印返回的错误信息
// readStream.on('error',(err)=>{
//     console.log(err);
// })


// fs.createWriteStream()  向文件流中写入数据
// var str = '';
// for(var i=0;i<8;i++){
//     str+='我是从数据库获取的数据，要保持起来\n';
// }
// var writeStream = fs.createWriteStream('./img/文本.txt');
// writeStream.write(str)
// // 标记写入完成
// writeStream.end();
// // 注意：想要触发这个事件，必须在前面标记写入完成 writeStream.end();
// writeStream.on('finish',()=>{
//     console.log('写入完成');
// })

//管道流   主要用来大规模复制文件
// 创建读取流
// var readStream = fs.createReadStream('./css/www.css');
// var readStream = fs.createReadStream('./img/文本.txt');
// // 创建写入流
// // 注意：写入流的路径必须是存在的，否则会报错
// var writeStream = fs.createWriteStream('./img/test/文本.txt',{flags:'a'});
// // 在写入之前，先添加一个换行符到目标文件
// writeStream.write('\n', (err) => {
//     if (err) {
//         console.error('Error writing newline:', err);
//         return;
//     }
// });
// // 把读取到的文件复制到写入流的路径当中去
// readStream.pipe(writeStream)


// existsSync 同步检查目录是否存在
// console.log(fs.existsSync('./img/test')); //true


// path 路径模块 和 url模块

// 引用 path 模块
const path = require('path');


// 1. path.join()：路径拼接
// 把多个路径片段拼接为完整的路径字符串
// 只要提供路径片段，就可以拼接成一个完整的路径
// fs.readFile(path.join(__dirname, 'img/文本.txt'), 'utf-8', (err, data)=>{
//     if(err) throw err
//     console.log(data);
// })


// 打印该文件所在磁盘的路径
// console.log(__dirname); // C:\Users\soso\Desktop\JavaScript

//引用模块 
// const fpath = '/img/文本.txt' //假设为文件存放的路径
// path.basename(): 获取路径中文件名
// var fullName = path.basename(fpath);
// console.log(fullName);  //文本.txt
// var fullName2 = path.basename(fpath,'.txt') 
// console.log(fullName2);  //文本


// path.extname()：获取路径中的文件扩展名
// const fpath = '/img/dog.gif' //假设为文件存放的路径
// const fullName = path.extname(fpath);
// console.log(fullName);//.gif


// url.parse()方法：接受一个URL字符串，返回一个URL对象。
// const url = require('url');
// // 示例URL字符串
// const urlString = 'https://www.example.com:8080/path/to/file?query=value#hash';
// // 解析URL字符串
// const parsedUrl = url.parse(urlString);
// // 输出解析结果
// console.log(parsedUrl); 


//加载 http 请求
var http = require("http");


// 调用 http.createServer() 方法，创建一个web服务器实例
// 创建http请求服务器
let server = http.createServer();
// 为服务器实例绑定 request 事件，监听客户端发送过来的网络请求。
// 接受客户端发送过来的request请求，并且返回结果
// server.on("request",(req, res)=>{
//     // req 是请求对象，它包含了与客户端相关的数据和属性，例如
//     // req.url 是客户端请求的 URL地址
//     // req.method 是客户端请求的 method 类型
//     const url = req.url
//     const method = req.method
//     const str = JSON.stringify({size:1, data:[{name:'测试一下',age:18}]}); //转为json字符串
//     // 设置CORS头部，允许所有源访问
//     res.setHeader('Access-Control-Allow-Origin', '*');
//     // 设置响应头，指定响应内容的类型和编码格式
//     // 解决中文乱码的问题
//     console.log(11,req.url);
    
//     res.setHeader('Content-Type','text/plain; charset=utf-8')
//     //调用 res.end() 方法，向客户端发送指定内容，并结束这次请求的处理过程
//     res.end(str)

//     //把本地的图片上传到服务器，然后返回给客户端
//     // if(req.url!=="/favicon.ico")
//     // fs.readFile('./img/dog.gif',(err,data)=>{ //注意如果是图片，不需要加utf-8
//     //     try{  // try是为了处理 err 报错
//     //         if(err) throw err;
//     //         res.end(data)
//     //     }catch(err){
    
//     //     }
//     // })
// })
// 调用服务器实例 的  .listen() 方法，启动当前的 web 服务器实例
// 设置端口号
// server.listen(5501,function(){
//     console.log('服务器启动成功了，可以通过访问http://127.0.0.1:5501');
// });




// Express 的基本使用 
// 1. 导入 express
const express = require('express')
const bodyParser = require('body-parser');
// 2. 创建 web 服务器
const app = express()
// 中间件
app.all('*',(req, res, next) => {
    console.log('正常连接');
    res.header('Access-Control-Allow-Origin', '*')  // 处理跨域
    res.header('Access-Control-Allow-Methods', 'POST,GET')  // 只允许POST和GET
    res.header('Access-Control-Allow-Headers', 'Content-Type'); // 允许的请求头
    next()  // 执行下一个中间件
})
// 使用body-parser中间件解析JSON请求体
app.use(bodyParser.json());

// 使用body-parser中间件解析URL编码的请求体
app.use(bodyParser.urlencoded({ extended: true }));

// 中间件函数，用于检查必传参数---适用于get请求
function checkRequiredParams(req, res, next) {    
    const { name, age } = req.body;
    // 检查参数是否存在
    if (!name || !age) {
      // 如果参数不存在，返回400错误和提示信息
      return res.status(400).json({ error: '缺少必传参数' });
    }
    // 如果参数存在，调用下一个中间件
    next();
}
  
// 4. 监听客户端的 GET 和 POST 请求，并向客户端响应具体的内容
app.post('/user', (req, res) => {
    // 调用 express 提供的 res.send() 方法，向客户端响应一个 JSON 对象    
    // res.send({name: 'zs', age: 20, gender: '男'})
    
    // 处理post请求
    const { name, age } = req.body;    
    
    // 检查参数是否存在
    if (!name || !age) {
      // 如果参数不存在，返回400错误和提示信息      
      return res.status(400).json({ error: '缺少必传参数' });
    }

    res.status(200).json({
        "code": 0,
        "msg": "OK",
        "data": {
          "list": [
            {
              "violation_id": 38913371952,
              "title": "发布风险商品信息",
              "start_time": "2024-06-25 18:15",
              "end_time": "2024-06-25 18:15",
              "point": 0,
              "reason": "您发布的商品涉嫌资金风险已被删除，请合规合法经营，切勿发布风险商品影响交易安全。",
              "result": "删除高风险商品",
              "status": 2,
              "status_name": "已处理",
              "user_name": "tb924343042",
              "shop_name": "田中君总是如此慵懒",
              "is_read": true,
              "notice_id": 0,
              "update_time": "2025-02-08 12:46"
            }
          ],
          "count": 31
        }
    });
    // 把本地的图片上传到服务器，然后返回给客户端
    // fs.readFile('./img/dog.gif',(err,data)=>{ //注意如果是图片，不需要加utf-8
    //     try{  // try是为了处理 err 报错
    //         if(err) throw err;            
    //         res.end(data);
    //     }catch(err){
    
    //     }
    // })
})
// 3. 启动服务器
// app.listen(80, ()=>{
//     console.log('express server runing at http://127.0.0.1');
// })


// Express路由的基本使用
// 创建路由模块
var router = express.Router();
// 在注册解析类型
router.use(bodyParser.json());
// 解析 application/x-www-form-urlencoded
router.use(bodyParser.urlencoded());

// 使用中间件函数
// 可在路由中间件函数中，对请求和响应对象进行处理
// 可检查请求参数，对请求参数进行处理，设置响应头等
// 可在res对象上设置属性，供后续中间件函数使用
// 以下两种是全局中间件函数，会在每次请求时都执行
router.use((req, res, next) => {
    res.params1 = '这是第一个中间件函数';
    next();
})
router.use((req, res, next) => {
  res.params2 = '这是第二个中间件函数';
  // console.log(res.params1); //可以在这里调用前面中间件函数的属性
  next();
})

// 局部中间件函数，只会在当前路由中间件函数中执行
// 定义局部生效的中间件函数
const mw1 = (req, res, next)=>{
	// console.log('调用了局部生效的中间件')
  // res.params3 = '这是第三个中间件函数';//注意局部中间件函数不能追加属性
  // 一般在局部中间件函数中，对请求和响应对象进行处理
	next()
}


// 一定要在路由之前，配置 cors 这个中间件，解决接口跨域问题
const cors = require('cors')
app.use(cors()) //允许所有源访问---相当于设置了Access-Control-Allow-Origin: *


// 托管静态的资源 
// 调用 express.static() 方法，对外提供静态资源
// 如果希望在托管的静态资源访问路径之前，挂载路径前缀（可以自定义）
app.use('/static',express.static('./img')) //比如访问一个图片：/static/spirit.png
 
// 使用局部中间件函数
router.get('/dynamics',mw1,(req,res)=>{
  res.send({name: 'zs', age: 20, gender: '男',params1: res.params1,params2: res.params2})
})
app.use('/',router)
// 启动服务
// app.listen(8800,'0.0.0.0', ()=>{  //如果想要别的电脑访问，需要设置0.0.0.0，意思是所有的ip都可以访问
//     console.log('express server runing at http://127.0.0.1');
// })
app.listen(8800, ()=>{  //仅限本地本机访问
  console.log('express server runing at http://127.0.0.1');
})